<?php

namespace app\web\controller;

use app\common\cachemodel\name_analyze\Zl9NameAnalyzeRecord;
use app\common\lib\Aes;
use app\common\lib\exception\ApiException;
use app\common\lib\Util;
use think\Controller;
use think\Env;

class HoroscopeDemo extends Controller
{
    public function createNamePersonal()
    {
        $this->assign('oss', Env::get('host.photo'));

        return $this->fetch();
    }

    public function createNameCompany()
    {
        $this->assign('oss', Env::get('host.photo'));

        return $this->fetch();
    }

    public function nameAnalyze()
    {
        $tokenParam = input('token/s', '');
        // access-token AES解密
        $str = (new Aes())->decryptWithOpenssl($tokenParam);
        if (empty($str))
        {
            throw new ApiException('名字评分参数错误');
        }
        parse_str($str, $params);
        $shareTo = (int)$params['share_to'];    // 1=>微信 2=>qq
        $id = (int)$params['id'];    // 起名记录ID
        //检查session，如果不存在，那么就直接跳转到登录
        $this->checkLogin($tokenParam, $shareTo);

        $this->assign('token', $tokenParam);
        $this->assign('oss', Env::get('host.photo'));
        return $this->fetch();
    }

    /**
     * 分享助力
     * @return \think\response\Json
     * @throws \Exception
     */
    public function nameAnalyzeShareHelp()
    {
        $token_param = input('token/s', '');
        // access-token AES解密
        $str = (new Aes())->decryptWithOpenssl($token_param);
        if (empty($str))
        {
            return show(config('code.error'), '服务异常，助力失败～');
        }
        parse_str($str, $params);
        $shareTo = (int)$params['share_to'];    // 1=>微信 2=>qq
        $id = (int)$params['id'];    // 起名记录ID
        if (!in_array($shareTo, [1, 2], true))
        {
            return show(config('code.success'), '请求成功');
        }
        if ($shareTo === 1)
        {   //  微信
            $avatar = session('name_analyze.headimgurl');
            $nickname = session('name_analyze.name');
            $unionid = session('name_analyze.unionid');
        } else
        {   //  QQ
            $avatar = session('qq.headimgurl');
            $nickname = session('qq.name');
            $unionid = session('qq.unionid');
        }
        if (!$unionid)
        {
            return show(config('code.success'), '请求成功');
        }
        $zl9NameAnalyzeRecord = new Zl9NameAnalyzeRecord();
        $data = $zl9NameAnalyzeRecord->getInfoById($id);
        if ($data['status'] !== 0)
        {
            return show(config('code.success'), '请求成功');
        }
        $shareHelpInfo = $data['share_help_info'];
        $isHelped = false;
        foreach ($shareHelpInfo as $shareItemData)
        {
            if ($shareItemData['share_to'] === $shareTo && $unionid === $shareItemData['unionid'])
            {
                $isHelped = true;
                break;
            }
        }
        if ($isHelped)
        {
            return show(config('code.success'), '请求成功');
        }
        $avatarInfo = Util::wxImgUploadOss($avatar, 'uploads/avatar');
        $avatar = $avatarInfo['success'] ? $avatarInfo['url'] : $avatar;
        $nowTime = time();
        $shareHelpInfo[] = [
            'share_to' => $shareTo,
            'avatar' => $avatar,
            'name' => $nickname,
            'unionid' => $unionid,
        ];
        $updateData = [
            'share_help_info' => $shareHelpInfo,
            'update_time' => $nowTime,
        ];
        $isUnlock = false;
        if (count($shareHelpInfo) >= 3)
        {
            $isUnlock = true;
            $updateData['status'] = 1;  //  解锁状态 0=>未解锁 1=>已解锁计算中 2=>已完成 3=>计算失败
            $updateData['unlock_type'] = 1;     //  解锁方式 1=>分享解锁 2=>微信解锁 3=>支付宝解锁 4=>准币解锁
            $updateData['start_time'] = $nowTime;
        }
        $res = $zl9NameAnalyzeRecord->UpdateData($id, $updateData);
        if ($res)
        {   //  解锁队列 添加
            if ($isUnlock)
            {   //  已解锁 添加解锁队列
                Util::queuePush('horoscope_name_analyze', ['id' => $id]);
            }
        }
        return show(config('code.success'), '请求成功');
    }

    /**
     * 微信登陆
     */
    public function weixin_login(): void
    {
        $token = urlencode(input('get.token/s'));
        $appid = config('wechat.mp_appid');
        $domain = Env::get('host.domain');
        $redirect_uri = urlencode($domain . '/web/horoscope_demo/weixin_back');
        header('location:https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $appid . '&redirect_uri=' . $redirect_uri . '&response_type=code&scope=snsapi_userinfo&state=' . $token . '#wechat_redirect');

        exit;
    }

    /**
     * 微信登陆返回
     */
    public function weixin_back(): void
    {
        $wechat_conf = config('wechat');
        $appid = $wechat_conf['mp_appid'];
        $appsecret = $wechat_conf['mp_secret'];
        $code = input('get.code/s');
        if (empty($code))
        {
            $this->error('微信授权失败！');
        }

        $token = urlencode(input('get.state/s'));
        if (empty($token))
        {
            $this->error('获取token失败！');
        }
        $access_token = session('name_analyze.access_token');
        if (empty($access_token) || $access_token === '')
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid . '&secret=' . $appsecret . '&code=' . $code . '&grant_type=authorization_code';
            $access_token = json_decode(file_get_contents($access_token_url), false);
            if (isset($access_token->errcode))
            {
                $this->error('授权失败');
            }
            session('name_analyze.access_token', $access_token->access_token);
            session('name_analyze.refresh_token', $access_token->refresh_token);
            session('name_analyze.openid', $access_token->openid);
        }

        $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . session('name_analyze.access_token') . '&openid=' . session('name_analyze.openid') . '&lang=zh_CN';
        $user_info = json_decode(file_get_contents($user_info_url), false);
        if (isset($user_info->errcode))
        {
            $access_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=' . $appid . '&grant_type=refresh_token&refresh_token=' . session('name_analyze.refresh_token');
            $access_token = json_decode(file_get_contents($access_token_url), true);
            if (isset($access_token['access_token'], $access_token['refresh_token'], $access_token['openid']) && !empty($access_token))
            {
                session('name_analyze.access_token', $access_token['access_token']);
                session('name_analyze.refresh_token', $access_token['refresh_token']);
                session('name_analyze.openid', $access_token['openid']);

                $user_info_url = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $access_token['access_token'] . '&openid=' . $access_token['openid'] . '&lang=zh_CN';
                $user_info = json_decode(file_get_contents($user_info_url), false);
                if (isset($user_info->errcode))
                {
                    echo '<h1>错误：</h1>' . $user_info->errcode;
                    echo '<br/><h2>错误信息：</h2>' . $user_info->errmsg;
                    exit;
                }
            } else
            {//失败的话，重新授权登录
                if (40001 === $user_info->errcode)
                {//40001为invalid credential, access_token is invalid or not latest, hints: [ req_id: EfKfY24ce-3ItL5 ]，清空access_token
                    session('name_analyze.access_token', null);
                }
                $this->redirect('/web/horoscope_demo/weixin_login?token=' . $token);
            }
        }
        //把unionid、headimgurl、name 保存到session里
        session('name_analyze.unionid', $user_info->unionid);
        session('name_analyze.headimgurl', $user_info->headimgurl);
        session('name_analyze.name', $user_info->nickname);
        session('name_analyze.sex', $user_info->sex);

        $this->redirect('/web/horoscope_demo/nameanalyze?token=' . $token);
    }

    /**
     * 检查session里是否有  unionid、headimgurl、name 这三个参数，如果为空，那么跳转到 微信 或者 qq 登录页面
     * @param string $token app邀请档案传过来的加密数据
     * @param int $share_to 【1：微信；2：qq】
     */
    private function checkLogin($token = '', $share_to = 1): void
    {
        if (1 === $share_to && (empty(session('name_analyze.unionid'))))
        {
            $this->redirect('/web/horoscope_demo/weixin_login?token=' . urlencode($token));
        } else if (2 === $share_to && (empty(session('qq.unionid')) || empty(session('qq.headimgurl')) || empty(session('qq.name'))))
        {
            $this->redirect('/web/horoscope_demo/qq?token=' . urlencode($token));
        }
    }

    public function qq(): void
    {
        $app_id = Env::get('qq.web_appid');
        $app_secret = Env::get('qq.web_appkey');
        $my_url = Env::get('qq.web_callback_url');
        //注  回调地址必须和该代码域名一致
        if (empty($_GET['code']))
        {//判断是否有code,若无code则去qq第三方接口请求授权
//            $_SESSION['state'] = md5(uniqid(rand(), true));//一串随机的字符串，用于回调时对比参数防止csrf攻击
            //拼接url地址同时url化回调地址并跳转
            $token = urlencode(input('get.token/s'));
            $url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' . $app_id . '&redirect_uri=' . urlencode($my_url) . '&state=' . urlencode($token);
            header('location: ' . $url);
        } else
        {
            $token = input('get.state/s');
            //省略一步  使用state判断是否csrf攻击   使用$_SESSION['state']和$_GET['state']进行对比判断授权过程是否被劫持
            //拼接url地址使用code请求并获得access_token
            $url = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=' . $app_id . '&client_secret='
                . $app_secret . '&code=' . $_GET['code'] . '&redirect_uri=' . $my_url;
            //发出请求
            $info = file_get_contents($url);
            //var_dump($info);由于传回来的数据是个字符串，不能直接使用，所以进行变量化
            $params = [];
            parse_str($info, $params);//把传回来的数据参数变量化
            //var_dump($params);变量化后的结果
            //判断access_token是否存在，如果不存在，那么让用户重新获取，例如：{"error":100019,"error_description":"code to access token error"}
            if (!isset($params['access_token']))
            {
                $this->redirect('/web/horoscope_demo/nameanalyze?token=' . $token);
            }
            //使用access_token去请求openid
            $graph_url = 'https://graph.qq.com/oauth2.0/me?access_token=' . $params['access_token'] . '&unionid=1';
            $str = file_get_contents($graph_url);
            //判断callback在字符串$str是否存在，如果存在则返回下标，否则false，下标不完全等于false，因为0会被判断为false
            if (strpos($str, 'callback') !== false)
            {
                $lpos = strpos($str, '(');//判断(出现的下标
                $rpos = strrpos($str, ')');//判断)出现的下标，加上r从右边开始查找
                $str = substr($str, $lpos + 1, $rpos - $lpos - 1);//截取字符串
                //从$rpos+1下标 { 处截取  $rpos - $lpos -1 位 ，此时$str的值就为一个json格式的数据了
            }
            $user = json_decode($str, true);//json转对象,存放有返回的数据 client_id ，openid
            //拼接url并访问，用access_token和openid得到用户信息
            $urls = 'https://graph.qq.com/user/get_user_info?access_token=' . $params['access_token'] . '&oauth_consumer_key=' . $app_id . '&openid=' . $user['openid'];
            $rs = file_get_contents($urls);
            $ref = json_decode($rs, true);//得到的用户信息

            //把unionid、headimgurl、name 保存到session里
            session('qq.unionid', $user['unionid']);
            session('qq.headimgurl', $ref['figureurl_qq_1'] ?? '');
            session('qq.name', $ref['nickname'] ?? '');
            session('qq.sex', $ref['gender_type']);

            $this->redirect('/web/horoscope_demo/nameanalyze?token=' . $token);
        }
    }
}